﻿using Abp.Net.Mail;
using Abp.Configuration;
using System.Threading.Tasks;
using System;
using System.Globalization;
using App.Configuration.Dto;
using System.Collections.Generic;
using Abp.Domain.Repositories;
using Abp.UI;
using Omu.ValueInjecter;
using App.BaseObject;
using System.Linq;
using EntityFramework.Extensions;
using Abp.Runtime.Session;
using Abp.Configuration.Startup;
using System.Data.Entity;

namespace App.Configuration
{
    public class SettingsAppService : AppServiceBase, ISettingsAppService
    {
        private readonly IMultiTenancyConfig _multiTenancyConfig;
        private readonly IEmailSender _emailSender;
        private readonly IRepository<Button> _buttonRepository;
        private readonly IRepository<MenuPermission> _menuRepository;

        public SettingsAppService(
            IMultiTenancyConfig multiTenancyConfig,
            IRepository<MenuPermission> menuRepository,
            IRepository<Button> buttonRepository,
            IEmailSender emailSender)
        {
            _multiTenancyConfig = multiTenancyConfig;
            _emailSender = emailSender;
            _buttonRepository = buttonRepository;
            _menuRepository = menuRepository;
        }

        public async Task<SettingsDto> GetAllSettings()
        {
            var hostSettings = new SettingsDto
            {
                General= new GeneralSettingsDto {
                    AppName = await SettingManager.GetSettingValueForApplicationAsync(AppSettings.General.AppName)
                }
            };

            //用户
            hostSettings.General.AppPageSize = await SettingManager.GetSettingValueAsync<int>(AppSettings.General.AppPageSize);

            //不启用多租户则获取
            if (!_multiTenancyConfig.IsEnabled) {
                hostSettings.Email = new EmailSettingsDto {
                    DefaultFromAddress = await SettingManager.GetSettingValueAsync(EmailSettingNames.DefaultFromAddress),
                    DefaultFromDisplayName = await SettingManager.GetSettingValueAsync(EmailSettingNames.DefaultFromDisplayName),
                    SmtpHost = await SettingManager.GetSettingValueAsync(EmailSettingNames.Smtp.Host),
                    SmtpPort = await SettingManager.GetSettingValueAsync<int>(EmailSettingNames.Smtp.Port),
                    SmtpUserName = await SettingManager.GetSettingValueAsync(EmailSettingNames.Smtp.UserName),
                    SmtpPassword = await SettingManager.GetSettingValueAsync(EmailSettingNames.Smtp.Password),
                    SmtpDomain = await SettingManager.GetSettingValueAsync(EmailSettingNames.Smtp.Domain),
                    SmtpEnableSsl = await SettingManager.GetSettingValueAsync<bool>(EmailSettingNames.Smtp.EnableSsl),
                    SmtpUseDefaultCredentials = await SettingManager.GetSettingValueAsync<bool>(EmailSettingNames.Smtp.UseDefaultCredentials)
                };
            }

            return hostSettings;
        }

        public async Task SendTestEmail(string toEmail)
        {
            var subject = L("TestEmail_Subject");
            var body = L("TestEmail_Body");

            await _emailSender.SendAsync(toEmail, subject, body);
        }

        public async Task UpdateAllSettings(SettingsDto input)
        {
            //administrator 系统拥有者能改
            if (!AbpSession.TenantId.HasValue)
            {
                await SettingManager.ChangeSettingForApplicationAsync(AppSettings.General.AppName, input.General.AppName);
            }

            //租户能改
            if (_multiTenancyConfig.IsEnabled && AbpSession.TenantId.HasValue)
            {
            }

            //用户能改
            await SettingManager.ChangeSettingForUserAsync(AbpSession.ToUserIdentifier(), AppSettings.General.AppPageSize, input.General.AppPageSize.ToString(CultureInfo.InvariantCulture));


            //不启用多租户则可用系统发送邮件
            if (!_multiTenancyConfig.IsEnabled) {
                //Email
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.DefaultFromAddress, input.Email.DefaultFromAddress);
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.DefaultFromDisplayName, input.Email.DefaultFromDisplayName);
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Host, input.Email.SmtpHost);
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Port, input.Email.SmtpPort.ToString(CultureInfo.InvariantCulture));
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.UserName, input.Email.SmtpUserName);
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Password, input.Email.SmtpPassword);
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Domain, input.Email.SmtpDomain);
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.EnableSsl, input.Email.SmtpEnableSsl.ToString(CultureInfo.InvariantCulture).ToLower(CultureInfo.InvariantCulture));
                await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.UseDefaultCredentials, input.Email.SmtpUseDefaultCredentials.ToString(CultureInfo.InvariantCulture).ToLower(CultureInfo.InvariantCulture));

            }
        }

        public async Task<List<MenuPermission>> GetAllMenuPermissions() {
            if (_multiTenancyConfig.IsEnabled && AbpSession.TenantId.HasValue)
                return await _menuRepository.GetAllListAsync(s => !s.IsHostTenant);

            return await _menuRepository.GetAllListAsync();
        }

        public async Task<MenuPermission> CreateMenu(MenuPermissionDto dto)
        {
            if (await _menuRepository.CountAsync(m => m.MenuText == dto.MenuText) > 0)
            {
                throw new UserFriendlyException(string.Format("名为【{0}】的菜单已经存在！", dto.MenuText));
            }

            var menu = new MenuPermission();
            menu.InjectFrom(dto);
            menu.AutoCreated = false;

            return await _menuRepository.InsertAsync(menu);
        }

        public async Task UpdateMenu(int id, MenuPermissionDto dto)
        {
            var menu = await _menuRepository.GetAsync(id);
            menu.InjectFrom(dto);
        }

        public async Task<List<Button>> GetAllButton()
        {
            return await _buttonRepository.GetAllListAsync();
        }

        public async Task SaveButtons(BulkDto<ButtonDto> bulks)
        {
            //批量插入
            foreach (var row in bulks.InsertedRows)
            {
                if (await _buttonRepository.CountAsync(b => b.ButtonName == row.ButtonName || b.ButtonLink == row.ButtonLink) > 0)
                {
                    throw new UserFriendlyException(string.Format("名为【{0}】的按钮或方法为【{1}】的按钮已经存在！", row.ButtonName, row.ButtonLink));
                }
                else
                {
                    var button = new Button();
                    button.InjectFrom(row);
                    await _buttonRepository.InsertAsync(button);
                }
            }
            //批量更新
            foreach (var row in bulks.UpdatedRows.Where(s => s.Id.HasValue))
            {
                var button = await _buttonRepository.GetAsync(row.Id.Value);
                button.InjectFrom(row);
            }

            //删除
            //删除
            foreach (var row in bulks.DeletedRows)
            {
                if (row.Id.HasValue)
                    await _buttonRepository.DeleteAsync(row.Id.Value);
            }
        }

        public async Task SaveMenuButtons(int id, BulkKeyDto<int> dto)
        {
            var menu = await _menuRepository.GetAllIncluding(s=>s.ChildMenuPermissions).FirstOrDefaultAsync(s=>s.Id == id);

            await SetMenuButtons(menu, dto.KeyList.ToArray());
        }

        public async Task DeleteMenuAsync(int id)
        {
            await _menuRepository.GetAll().Where(s => s.Id == id).DeleteAsync();
        }

        #region set role permissions
        private async Task SetMenuButtons(MenuPermission menu, int[] buttonIds)
        {
            var allButtonText = await _buttonRepository.GetAllListAsync(s => buttonIds.Contains(s.Id));
            //Remove from removed roles
            foreach (var button in await GetAllButtonByMenuId(menu.Id))
            {
                var buttonMenu = await _menuRepository.GetAsync(button.Id);
                if (allButtonText.Select(s=>s.ButtonName).All(buttonText => buttonMenu.MenuText != buttonText))
                {
                    await RemoveFromMenusAsync(menu.Id, buttonMenu.MenuText);
                }
            }

            //Add to added roles
            foreach (var buttonId in buttonIds)
            {
                var button = await _buttonRepository.GetAsync(buttonId);
                if (menu.ChildMenuPermissions.All(ur => ur.MenuText != button.ButtonName))
                {
                    await AddToMenusAsync(menu.Id, button);
                }
            }
        }
        public async Task<List<MenuPermission>> GetAllButtonByMenuId(int menuId)
        {
            var data = new List<MenuPermission>();
            var menuButtons = await _menuRepository.GetAllListAsync(s => s.ParentId == menuId && s.MenuType == "button");
            foreach (var button in menuButtons)
            {
                var menuPermission = _menuRepository.FirstOrDefault(button.Id);
                if (menuPermission != null && data.Count(s => s.Id == button.Id) == 0) data.Add(menuPermission);
            }

            return data;
        }
        private async Task AddToMenusAsync(int menuId, Button button)
        {
            await _menuRepository.InsertAsync(new MenuPermission {
                MenuText = button.ButtonName,
                MenuLink = button.ButtonLink,
                MenuType = "button",
                IconCls = button.IconCls,
                IsActivated = "on",
                AutoCreated = true,
                ParentId = menuId
            });
        }
        private async Task RemoveFromMenusAsync(int menuId, string buttonText)
        {
            await _menuRepository.DeleteAsync(s => s.ParentId == menuId && s.MenuText == buttonText);
        }
        #endregion
    }
}
